/**
 * This is the main test file.
 * The test should be compiled this one of the flag:
 * 				USE_WF_QUEUE, USE_LOCK_QUEUE, USE_HP_QUEUE
 * Each flag defines the queue that whould be tested.
 */
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <glib.h>

#ifdef USE_WF_QUEUE
#include "WFQueue.h"
#define QUEUE WFQueue
#define PrintQueueType printf("\tUsing WFQueue\n");
#endif
#ifdef USE_optWF_QUEUE
#include "optWFQueue.h"
#define QUEUE optWFQueue
#define PrintQueueType printf("\tUsing optWFQueue\n");
#endif
#ifdef USE_LOCK_QUEUE
#include "LockQueue.h"
#define QUEUE LockQueue
#define PrintQueueType printf("\tUsing LockQueue\n");
#endif
#ifdef USE_HP_QUEUE
#include "HPQueue.h"
#define QUEUE HPQueue
#define PrintQueueType printf("\tUsing HPQueue\n");
#endif

#ifdef USE_HP
#define PrintHP printf("\tUsing HP\n");
#else
#define PrintHP printf("\tNot Using HP\n");
#endif


/**
 * run data
 */
int ITER, NUM_OF_THREADS;

/**
 * Parameters for the thread
 */
typedef struct Data_t {
	QUEUE *queue;
	int tid;
} Data;

/**
 * Thread main function
 */
void* thread_func(void *ptr) {
	Data *data = (Data*)ptr;
	int val;
	for (int i=0; i<ITER; i++) {
		if ( rand()>(RAND_MAX/2.0))
			enq(data->queue, data->tid, 0);
		else{
			val = deq(data->queue, data->tid);
			if (val != -1 && val != 0){
				printf("0) ERROR in thread %d!!! got unknown value %d\n\t", data->tid, val);
			}
		}
	}
	return 0;
}

/**
 * Main
 */
int main(int argc, char *argv[]) {
	if (argc != 3)
	{
		printf("usage: ./queue.exe NUM_OF_THREADS ITER\n");
		exit(-1);
	}
	//timer
	float totalTime = 0;
	GTimer* timer = g_timer_new();
	g_timer_start(timer);

	srand((unsigned)(time(0)));

	NUM_OF_THREADS = atoi(argv[1]);
	ITER = atoi(argv[2]);

	printf("\n*********************************************\n");
	printf("\tNUM_OF_THREADS=%d, ITER=%d\n",NUM_OF_THREADS, ITER);
	PrintQueueType;
	PrintHP;
	printf("*********************************************\n");

	/**********************************************************************/
	Data tData[NUM_OF_THREADS];
	QUEUE* queue = getQueue(NUM_OF_THREADS);

	pthread_t threads1[NUM_OF_THREADS];

	for (int i=0; i<NUM_OF_THREADS; i++){
		tData[i].queue = queue;
		tData[i].tid = i;
		pthread_create(&threads1[i], NULL, thread_func, (void*)&tData[i]);
	}

	for (int i=0; i<NUM_OF_THREADS; i++) {
		pthread_join(threads1[i], NULL);
	}

	printQueueSize(queue);
	deleteQueue(queue);

	g_timer_stop(timer);
	totalTime = g_timer_elapsed(timer, NULL);
	g_timer_destroy(timer);

	printf("*********************************************\n");
	printf("Finished in %f \n",totalTime);
	printf("*********************************************\n\n");
	return 0;
}

